package org.gikolet.ch2.android.dao;

import org.gikolet.ch2.android.dao.Schema.Boards;
import org.gikolet.ch2.android.dao.Schema.ThreadHeaders;
import org.gikolet.ch2.android.dao.Schema.ThreadHeaders.Columns;
import org.gikolet.ch2.dao.DaoException;
import org.gikolet.ch2.dao.ThreadHeaderDao;
import org.gikolet.ch2.data.ThreadHeader;

import roboguice.inject.ContextScoped;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteConstraintException;
import android.database.sqlite.SQLiteDatabase;

import com.google.inject.Inject;

@ContextScoped
public class AndroidThreadHeaderDao implements ThreadHeaderDao {

	private static final String[] COLUMNS = {
			ThreadHeaders.Columns.ID.column(),
			ThreadHeaders.Columns.BOARD_ID.column(),
			ThreadHeaders.Columns.LAST_MODIFIED.column(),
			ThreadHeaders.Columns.BYTE_SIZE.column() };

	private static final String SELECTION_ID = ThreadHeaders.Columns.ID
			.column()
			+ " = ?";

	@Inject
	private SQLiteDatabase db;

	public AndroidThreadHeaderDao() {
	}

	public void create(ThreadHeader threadHeader) {
		try {
			ContentValues cv = ThreadHeaders.convert(threadHeader);
			cv.remove(ThreadHeaders.Columns.ID.column());

			long rowId = this.db
					.insertOrThrow(ThreadHeaders.TBL_NAME, null, cv);

			threadHeader.setId(rowId);

		} catch (SQLiteConstraintException e) {
			throw new DaoException(DaoException.Error.CONSTRAINT, e);

		} catch (SQLException e) {
			throw new DaoException(DaoException.Error.ERROR, e);
		}
	}

	public ThreadHeader find(Long id) {
		String[] selectionArgs = { String.valueOf(id) };

		Cursor c = null;

		try {
			c = this.db.query(ThreadHeaders.TBL_NAME, COLUMNS, SELECTION_ID,
					selectionArgs, null, null, null);

			if (!c.moveToFirst()) {
				throw new DaoException(DaoException.Error.NOT_FOUND);
			}

			return ThreadHeaders.convert(c);

		} catch (SQLException e) {
			throw new DaoException(DaoException.Error.ERROR, e);

		} finally {
			if (c != null) {
				try {
					c.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public ThreadHeader find(String hostName, String path, String threadKey) {
		String tables = ThreadHeaders.TBL_NAME + " T INNER JOIN "
				+ Boards.TBL_NAME + " B ON (T."
				+ ThreadHeaders.Columns.BOARD_ID.column() + " = " + "B."
				+ Boards.Columns.ID.column() + ")";

		String[] columns = { "T." + ThreadHeaders.Columns.ID.column()+" AS "+ThreadHeaders.Columns.ID.column(),
				"B." + Boards.Columns.HOST_NAME.column()+" AS "+Boards.Columns.HOST_NAME.column(),//
				"B." + Boards.Columns.PATH.column()+" AS "+Boards.Columns.PATH.column(),//
				"B." + Boards.Columns.NAME.column() +" AS "+Boards.Columns.NAME.column(),//
				"T."+Columns.THREAD_KEY.column()+" AS "+Columns.THREAD_KEY.column(),//
				"T."+Columns.SUBJECT.column()+" AS "+Columns.SUBJECT.column(),
				"T."+Columns.RES_COUNT.column()+" AS "+Columns.RES_COUNT.column(),
				"T."+Columns.DATE.column()+" AS "+Columns.DATE.column(),
				"T."+Columns.LAST_MODIFIED.column()+" AS "+Columns.LAST_MODIFIED.column(),
				"T."+Columns.BYTE_SIZE.column()+" AS "+Columns.BYTE_SIZE.column()
		};

		String where = "B." + Boards.Columns.HOST_NAME.column() + " = ? AND B."
				+ Boards.Columns.PATH.column() + " = ? AND "
				+ "T."+ThreadHeaders.Columns.THREAD_KEY.column() +" = ?";

		String[] whereArgs = { hostName.toString(), path.toString(),
				threadKey.toString() };

		Cursor c = null;

		try {
			c = this.db.query(tables, columns, where, whereArgs, null, null,
					null);

			if (!c.moveToFirst()) {
				throw new DaoException(DaoException.Error.NOT_FOUND);
			}

			return ThreadHeaders.convert(c);

		} catch (SQLException e) {
			throw new DaoException(DaoException.Error.ERROR, e);

		} finally {
			if (c != null) {
				try {
					c.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public void update(ThreadHeader threadHeader) {
		ContentValues cv = ThreadHeaders.convert(threadHeader);
		cv.remove(ThreadHeaders.Columns.ID.column());

		String[] whereArgs = { String.valueOf(threadHeader.getId()) };

		try {

			int count = this.db.update(ThreadHeaders.TBL_NAME, cv,
					SELECTION_ID, whereArgs);

			if (count == 0) {
				throw new DaoException(DaoException.Error.NOT_FOUND);
			}

		} catch (SQLException e) {
			throw new DaoException(DaoException.Error.ERROR, e);
		}
	}

	public void delete(Long id) {
		String[] whereArgs = { id.toString() };

		try {
			int count = this.db.delete(ThreadHeaders.TBL_NAME, SELECTION_ID,
					whereArgs);

			if (count == 0) {
				throw new DaoException(DaoException.Error.NOT_FOUND);
			}

		} catch (SQLException e) {
			throw new DaoException(DaoException.Error.ERROR, e);
		}
	}
}
